I thought that JavaScript's loose equality operator was being nice and letting me compare Numbers with BigInts:
42 == 42n // true!
So I tried a number bigger than Number.MAX_SAFE_INTEGER. I figured that since the number gets rounded up automatically, I might have to round up the BigInt as well for them to be considered equal:
9999999999999999 == 10000000000000000 // true - rounded to float64
9999999999999999 == 9999999999999999n // false - makes sense!
10000000000000000 == 9999999999999999n // false - makes sense!
9999999999999999 == 10000000000000000n // true - makes sense!
Great, makes sense — so then I tried another big number that gets rounded up:
18446744073709551616 == 18446744073709552000 // true - rounded to float64
18446744073709551616 == 18446744073709551616n // true?!
18446744073709552000 == 18446744073709551616n // true?!
18446744073709551616 == 18446744073709552000n // false?!
I observed the same results in Chrome, Safari, and Node.js.
Why isn't this behavior consistent? Is it because the numbers are compared as mathematical values, and what does that mean?
My guess is that this is due to the exact implementation of mathematical value not being specified (or at least I couldn't find it).
The abstract equality comparison is specified https://262.ecma-international.org/11.0/#sec-abstract-equality-comparison
If Type(x) is BigInt and Type(y) is Number, or if Type(x) is Number and Type(y) is BigInt, then
If x or y are any of NaN, +∞, or -∞, return false.
If the mathematical value of x is equal to the mathematical value of y, return true; otherwise return false.
So a BigInt should have a mathematical value of some integer, and a Number should have a mathematical value of some kind of scientific notation number, and so the comparisons should be intuitive, but exactly how your JS engine implements mathematical value is not following the spec in spirit.